<?php
defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * 通用模块初始化
 */

// ------------------------------------------------------------------------

class Threads extends CI_Model
{

    private static $mysql_config;

    public function __construct()
    {
        parent::__construct();
        static $instance = FALSE;
        if (!$instance && $instance = TRUE) {
            // 只会在第一次初始化的时候调用一次
            $db = require_once(APPPATH . 'config/' . ENVIRONMENT . '/db.php');
            $config = $db[config_item('default_db')];
            self::$mysql_config = array(
                'host' => $config['host'],
                'port' => $config['port'],
                'user' => $config['user'],
                'password' => $config['passwd'],
                'database' => $config['name'],
            );
        }
    }

    /**
     * 自动加载并返回 model 字文件夹中的模型
     * 命名规则如：models/swoole/Client_swoole.php
     *
     * @param string $model_name model的名称（省略 _mysql 后缀）
     * @param string $type model 的子文件夹名
     * @return object
     */
    public function model($model_name, $type = 'mysql')
    {
        $alias = $model_name . '_' . $type;
        $model_name = 'demo/' . $type . '/' . ucfirst($model_name . '_' . $type);
        if ($load = $this->load->is_loaded($model_name)) {
            return $this->$load;
        } else {
            $this->load->model($model_name, $alias);
            return $this->$alias;
        }
    }

    /**
     * 异步 mysql 客户端操作
     * 不同于框架自带的 mysql 类，该方法对于执行 mysql 命令是非阻塞的
     *
     * 调用示例：
     * $this->initialization->async_mysql('show tables',function($db,$result){
     *      var_dump($result, $db->affected_rows, $db->insert_id);
     * });
     * 其中 $db 是操作的 swoole_mysql 类；$result 将会直接返回结果集（如果有的话，否则将会返回 bool 表示是否执行成功）
     *
     * @param string $sql 需要执行的 sql 语句
     * @param closure $success 操作成功以后的回调方法，需要带有参数 $db 和 $result
     * @param bool $need_escape 是否需要转义 sql 中的特殊字符（需要支持 mysqlnd 扩展）
     * @return void
     */
    public function async_mysql($sql, $success, $need_escape = TRUE)
    {
        $mysql = new swoole_mysql;
        $mysql->connect(self::$mysql_config, function ($db, $result) use ($sql, $success, $need_escape) {
            if ($need_escape && method_exists($db, 'escape')) $sql = $db->escape($sql);
            if ($result === FALSE) {
                var_dump($db->connect_errno, $db->connect_error);
                die;
            }
            echo $sql . PHP_EOL;
            $db->query($sql, function ($db, $result) use ($success) {
                if ($result === FALSE) {
                    var_dump($db->error, $db->errno);
                } else {
                    $success($db, $result);
                }
                $db->close();
            });
        });
        $mysql->on('Close', function ($db) {
            echo "MySQL connection is closed." . PHP_EOL;
        });
    }

    /**
     * 通过输入“列名=>值”对照数组生成相应的 mysql SET 从句
     * 支持 insert 和 update 两种方式，可以使用别名
     *
     * @param array $data 需要插入数据库中的数据，键值对应
     * @param string $method 生成的 SET 从句类型，有 insert 和 update 两种形式
     * @param string $alias 数据表的别名，默认为空
     * @return string
     */
    public function replace_sql(array $data, $method = 'update', $alias = '')
    {
        $new_data = array();
        foreach ($data as $key => $item) {
            if ($alias) {
                $new_data["$alias.$key"] = "'$item'";
            } else {
                $new_data["`$key`"] = "'$item'";
            }
        }
        $data = $new_data;
        switch ($method) {
            case 'insert':
                $return = "(" . implode(',', array_keys($data)) . ") VALUES (" . implode(',', array_values($data)) . ")";
                break;
            case 'update':
                $mixed = array();
                foreach ($data as $key => $item) {
                    $mixed[] = "$key=$item";
                }
                $return = implode(',', $mixed);
                break;
            default:
                echo 'unknow method ' . $method . PHP_EOL;
                exit();
        }
        return $return;
    }

}